﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace LModBusRTU
{
    public delegate void EventLogCallBack(object sender, EventLogEntryType EventType, string EventInfo, int EventCode);
    public enum ModbusCommand : int
    {
        ReadBitReg_0x01 = 0x01,  // 读取线圈
        WriteBitReg_0x05 = 0x05,  // 写入单个线圈
        ReadInputReg_0x04 = 0x04,  // 读取输入寄存器 4x
        ReadMemoryReg_0x03 = 0x03,  // 读取保持寄存器 3x
        WriteOneMemReg_0x06 = 0x06,  // 写入单个寄存器
        WriteMemoryReg_0x10 = 0x10,// 写入保持寄存器
        RWMemoryReg_0x17 = 0x17,  // 读写保持寄存器

        HBHCCommand_0x41 = 0x41,
        HBHCCommand_0x42 = 0x42,
        /*
         // HBHCCommand_0x42协议格式：
         // 命令头：10字节
         [0]:    本机地址
         [1]:    扩展命令代码
         [2-3]:  主命令代码,RegWriteAddress
         [4-5]:  子命令代码,RegReadAddress
         [6-7]:  秘钥代码,RegReadCount
         [8-9]:  携带数据的数据量，单位：字节 ；必须是2的整数倍   
         */

    }
    public enum ByteEndian : int
    {
        BigEndian = 1, //高位在前
        LittleEndian = 2, // 低位在前
    }

    public delegate void TMBCommandResponCallBack(object sender);
    /// <summary>
    /// Modbus基础命令对象
    /// V2:20161213
    /// 修改：增加自定义命令：HBHCCommand_0x41
    /// V2:20170205
    /// 修改：命令：HBHCCommand_0x41处理机制修改
    /// </summary>
    public class TModbusRTUCommandV2
    {
        #region 成员
        public event TMBCommandResponCallBack OnGetRTURespon;
        public int ErrorCode { get; set; }
        /// <summary>
        /// 地址域，单元标识
        /// </summary>
        public byte PLCAddress { get; set; }
        /// <summary>
        /// Modbus命令代码
        /// </summary>
        public ModbusCommand Command { get { return fCommand; } }
        protected ModbusCommand fCommand = ModbusCommand.ReadInputReg_0x04;
        /// <summary>
        /// 读取寄存器地址，单写入命令时无效
        /// </summary>
        public ushort RegReadAddress { get; set; }
        /// <summary>
        /// 主命令代码,RegWriteAddress
        /// </summary>
        public ushort MainCode
        {
            get
            {
                if (fCommand == ModbusCommand.HBHCCommand_0x42)
                    return RegWriteAddress;
                else
                    return 0;
            }
            set { RegWriteAddress = value; }
        }
        /// <summary>
        /// 子命令代码,RegReadAddress
        /// </summary>
        public ushort SubCode
        {
            get
            {
                if (fCommand == ModbusCommand.HBHCCommand_0x42)
                    return RegReadAddress;
                else
                    return 0;
            }
            set { RegReadAddress = value; }
        }
        /// <summary>
        /// 秘钥代码,RegReadCount
        /// </summary>
        public ushort CryptKey
        {
            get
            {
                if (fCommand == ModbusCommand.HBHCCommand_0x42)
                    return RegReadCount;
                else
                    return 0;
            }
            set { RegReadCount = value; }
        }
        /// <summary>
        /// 写入寄存器地址，单读取命令时无效
        /// </summary>
        public ushort RegWriteAddress { get; set; }
        /// <summary>
        /// 读取寄存器数量，单写入命令时无效
        /// </summary>
        public ushort RegReadCount { get; set; }
        /// <summary>
        /// 写入寄存器数量，单读取命令时无效
        /// </summary>
        public ushort RegWriteCount
        {
            get { return (ushort)fRegValue.Length; }
            set { fRegValue = new ushort[value]; }
        }
        /// <summary>
        /// 要写入的寄存器数据，单读取命令时无效
        /// </summary>
        public ushort[] RegValue
        {
            get { return fRegValue; }
            set { fRegValue = value; }
        }
        protected ushort[] fRegValue = new ushort[0];
        /// <summary>
        /// 命令是否收到应答
        /// </summary>
        public bool HasReply { get { return fHasReply; } }
        protected bool fHasReply = false;

        //protected ushort[] fReplyValues = new ushort[0];
        /// <summary>
        /// 命令收到应答中携带的寄存器数据
        /// </summary>
        public ushort[] ReplyValues { get; set; }

        #endregion
        public TModbusRTUCommandV2() : this(ModbusCommand.ReadMemoryReg_0x03)
        {
            ErrorCode = 0;
            RegReadAddress = 0;
            RegWriteAddress = 0;
            RegReadCount = 0;
            RegWriteCount = 0;
            ReplyValues = new ushort[0];
        }
        public TModbusRTUCommandV2(ModbusCommand MBCommand)
        {
            fCommand = MBCommand;
        }
        /// <summary>
        /// 获得Modbus命令帧数据流，无CRC校验，建议将CRC放在发送层（数据链路层）处理
        /// </summary>
        /// <param name="PacketData"></param>
        /// <returns></returns>
        public int GetPacketDataNoCRC(out byte[] PacketData)
        {
            PacketData = new byte[0];
            int fResult = 0;
            List<byte> fDBuf = new List<byte>();
            fDBuf.Add(this.PLCAddress);
            fDBuf.Add((byte)fCommand);
            switch (fCommand)
            {
                case ModbusCommand.ReadBitReg_0x01:
                    if (this.RegReadCount > 0x7D0)
                        fResult = -3;
                    else
                    {
                        fDBuf.AddRange(GetBytes(this.RegReadAddress));
                        fDBuf.AddRange(GetBytes(this.RegReadCount));
                    }
                    break;
                case ModbusCommand.WriteBitReg_0x05:
                    if (this.RegReadCount != 1)
                        fResult = -3;
                    else
                    {
                        fDBuf.AddRange(GetBytes(this.RegReadAddress));
                        if (this.RegValue[0] == 0)
                            fDBuf.AddRange(GetBytes(0));
                        else
                            fDBuf.AddRange(GetBytes(0xFF00));
                    }
                    break;
                case ModbusCommand.ReadInputReg_0x04:
                case ModbusCommand.ReadMemoryReg_0x03:
                    if (this.RegReadCount > 0x7D)
                        fResult = -3;
                    else
                    {
                        fDBuf.AddRange(GetBytes(this.RegReadAddress));
                        fDBuf.AddRange(GetBytes(this.RegReadCount));
                    }
                    break;
                case ModbusCommand.WriteMemoryReg_0x10:
                    if (this.RegWriteCount > 0x7B)
                        fResult = -3;
                    else
                    {
                        fDBuf.AddRange(GetBytes(this.RegWriteAddress));
                        fDBuf.AddRange(GetBytes(this.RegWriteCount));
                        fDBuf.Add((byte)(this.RegWriteCount * 2));
                        for (int i = 0; i < this.RegValue.Length; i++)
                            fDBuf.AddRange(GetBytes(RegValue[i], 2));
                    }
                    break;
                case ModbusCommand.WriteOneMemReg_0x06:
                    if (this.RegWriteCount != 1)
                        fResult = -3;
                    else
                    {
                        fDBuf.AddRange(GetBytes(this.RegWriteAddress));
                        fDBuf.AddRange(GetBytes(RegValue[0]));
                    }
                    break;
                case ModbusCommand.RWMemoryReg_0x17:
                    if ((this.RegReadCount > 0x7D) || (this.RegWriteCount > 0x79))
                        fResult = -3;
                    else
                    {
                        fDBuf.AddRange(GetBytes(this.RegReadAddress));
                        fDBuf.AddRange(GetBytes(this.RegReadCount));
                        fDBuf.AddRange(GetBytes(this.RegWriteAddress));
                        fDBuf.AddRange(GetBytes(this.RegWriteCount));
                        fDBuf.Add((byte)(this.RegWriteCount * 2));
                        for (int i = 0; i < this.RegValue.Length; i++)
                            fDBuf.AddRange(GetBytes(RegValue[i], 2));
                    }
                    break;
                case ModbusCommand.HBHCCommand_0x41:
                    if ((this.RegReadCount > 0x7D) || (this.RegWriteCount > 0x79))
                        fResult = -3;
                    else
                    {
                        // 修改：2017-02-04
                        fDBuf.AddRange(GetBytes(this.RegReadAddress));
                        fDBuf.AddRange(GetBytes(this.RegReadCount));
                        fDBuf.AddRange(GetBytes(this.RegWriteAddress));
                        fDBuf.AddRange(GetBytes(this.RegWriteCount));
                        for (int i = 0; i < this.RegValue.Length; i++)
                            fDBuf.AddRange(GetBytes(RegValue[i], 2));
                    }
                    break;
                case ModbusCommand.HBHCCommand_0x42:
                    {
                        // 修改：2018-06-04                        
                        fDBuf.AddRange(GetBytes(this.RegWriteAddress));
                        fDBuf.AddRange(GetBytes(this.RegReadAddress));
                        fDBuf.AddRange(GetBytes(this.RegReadCount));
                        fDBuf.AddRange(GetBytes(this.RegValue.Length * 2));
                        for (int i = 0; i < this.RegValue.Length; i++)
                            fDBuf.AddRange(GetBytes(RegValue[i], 2));
                    }
                    break;
            }
            if (fResult >= 0)
            {
                fResult = fDBuf.Count;
                PacketData = fDBuf.ToArray();
            }
            return fResult;
        }

        public byte[] GetPacketDataNoCRC()
        {
            byte[] fPacketData = new byte[0];
            GetPacketDataNoCRC(out fPacketData);
            return fPacketData;
        }
        /// <summary>
        /// 获得串口通讯用Modbus数据帧，已经附加CRC校验码
        /// </summary>
        /// <param name="PacketData"></param>
        /// <returns></returns>
        public int GetSeialPortPacketData(out byte[] PacketData, TCRC16Endian fCRCEndian)
        {
            List<byte> fDBuf = new List<byte>();
            int fResult = GetPacketDataNoCRC(out PacketData);
            if (fResult > 0)
            {
                fDBuf = new List<byte>(PacketData);
                int fCRC16 = CRC16_GB19582.CRC16GB(PacketData, fCRCEndian);
                fDBuf.Add((byte)((fCRC16 >> 8) & 0xFF));
                fDBuf.Add((byte)(fCRC16 & 0xFF));
                fResult += 2;
                PacketData = fDBuf.ToArray();
            }
            return fResult;
        }
        /// <summary>
        /// 检查收到的数据是否当前命令的应答
        /// </summary>
        /// <param name="ReplyDatas"></param>
        /// <returns>正确返回1，否则返回<0;</returns>
        public int CheckReply(byte[] ReplyDatas)
        {
            int fErrorCode = 0;
            if (ReplyDatas == null)
                fErrorCode = -1;
            else
            {
                if (ReplyDatas.Length < 3)
                    fErrorCode = -2;
                if ((fErrorCode >= 0) &&
                    ((ReplyDatas[0] == this.PLCAddress) || (this.PLCAddress == 0))
                    && (ReplyDatas[1] == (int)this.Command))    // 命令相同
                    switch (this.Command)
                    {
                        case ModbusCommand.ReadBitReg_0x01:
                            if ((ReplyDatas.Length - 3 == ReplyDatas[2]) && (ReplyDatas[2] > 0))               // 收到数据与标识的数据长度相符
                            {
                                int fValueCount = ReplyDatas[2];
                                ReplyValues = new ushort[fValueCount];
                                for (int i = 0; i < fValueCount; i++)
                                {
                                    ReplyValues[i] = ReplyDatas[i + 3];
                                }
                                fErrorCode = 1;
                            }
                            break;
                        case ModbusCommand.ReadInputReg_0x04:
                        case ModbusCommand.ReadMemoryReg_0x03:
                        case ModbusCommand.RWMemoryReg_0x17:
                            // 协议中字节数为全部字节数量
                            if ((ReplyDatas.Length - 3 == ReplyDatas[2]) && (ReplyDatas[2] > 0) &&
                                (ReplyDatas[2] / 2 == this.RegReadCount))              // 收到数据与标识的数据长度相符
                            {
                                ReplyValues = new ushort[this.RegReadCount];
                                for (int i = 0; i < this.RegReadCount; i++)
                                {
                                    ReplyValues[i] = ReplyDatas[2 * i + 3];
                                    ReplyValues[i] = (ushort)((ReplyValues[i] << 8) | ReplyDatas[2 * i + 4]);
                                }
                                fErrorCode = 1;

                                if (this.PLCAddress == 0)
                                    this.PLCAddress = ReplyDatas[0];
                            }
                            break;
                        case ModbusCommand.WriteBitReg_0x05:
                        case ModbusCommand.WriteOneMemReg_0x06:
                        case ModbusCommand.WriteMemoryReg_0x10:
                            if (ReplyDatas.Length == 6)
                            {
                                int fWriteAddress = ReplyDatas[2];
                                fWriteAddress <<= 8;
                                fWriteAddress |= ReplyDatas[3];
                                int fWriteCount = ReplyDatas[4];
                                fWriteCount <<= 8;
                                fWriteCount |= ReplyDatas[5];
                                if ((fWriteAddress == this.RegWriteAddress) &&
                                    ((this.Command == ModbusCommand.WriteOneMemReg_0x06) || (fWriteCount == this.RegWriteCount)))
                                    fErrorCode = 1;
                                if ((fErrorCode == 1) && (this.Command == ModbusCommand.WriteOneMemReg_0x06))
                                {
                                    ReplyValues = new ushort[1];
                                    ReplyValues[0] = ReplyDatas[4];
                                    ReplyValues[0] = (ushort)((ReplyValues[0] << 8) | ReplyDatas[5]);
                                }
                            }
                            break;
                        case ModbusCommand.HBHCCommand_0x41:
                            if (ReplyDatas.Length >= 9)
                            {
                                // 修正：2017-02-04
                                // ReplyDatas[2-3]      ：读取地址
                                // ReplyDatas[4-5]      ：实际读取数量
                                // ReplyDatas[6-7]      ：写入地址
                                // ReplyDatas[8-9]      ：实际写入数量
                                // 该命令中，实际读取数量字节长度为2字节整数，因此可以传输0xFFFF字节数据
                                int fReadAddress = ReplyDatas[2];
                                fReadAddress = (fReadAddress << 8) | ReplyDatas[3];
                                int fReadLen = ReplyDatas[4];
                                fReadLen = (fReadLen << 8) | ReplyDatas[5];
                                int fWriteAddress = ReplyDatas[6];
                                fWriteAddress = (fWriteAddress << 8) | ReplyDatas[7];
                                int fWriteLen = ReplyDatas[8];
                                fWriteLen = (fWriteLen << 8) | ReplyDatas[9];
                                // 协议中字节数为全部字节数量
                                if ((ReplyDatas.Length - 10 == fReadLen * 2) && (fReadAddress == this.RegReadAddress)
                                    && (fWriteAddress == this.RegWriteAddress) && (fWriteLen == this.RegWriteCount))    // 收到数据与标识的数据长度相符
                                {
                                    this.RegReadCount = (ushort)fReadLen;
                                    ReplyValues = new ushort[this.RegReadCount];
                                    for (int i = 0; i < this.RegReadCount; i++)
                                    {
                                        ReplyValues[i] = ReplyDatas[2 * i + 10];
                                        ReplyValues[i] = (ushort)((ReplyValues[i] << 8) | ReplyDatas[2 * i + 11]);
                                    }
                                    fErrorCode = this.RegReadCount > 0 ? this.RegReadCount : 1;
                                }
                            }
                            break;


                        case ModbusCommand.HBHCCommand_0x42:
                            if (ReplyDatas.Length >= 10)
                            {
                                // 修正：2017-06-04    
                                // 主命令代码,RegWriteAddress
                                int fRegWriteAddress = ReplyDatas[2];
                                fRegWriteAddress = (fRegWriteAddress << 8) | ReplyDatas[3];
                                // 子命令代码,RegReadAddress
                                int fReadAddress = ReplyDatas[4];
                                fReadAddress = (fReadAddress << 8) | ReplyDatas[5];
                                // 秘钥代码,RegReadCount
                                int fReadCount = ReplyDatas[6];
                                fReadCount = (fReadCount << 8) | ReplyDatas[7];
                                // 携带数据的数据量，单位：字节；必须是2的整数倍
                                int fDataLen = ReplyDatas[8];
                                fDataLen = (fDataLen << 8) | ReplyDatas[9];

                                // 协议中字节数为全部字节数量
                                if ((ReplyDatas.Length - 10 == fDataLen) &&
                                    (fDataLen % 2 == 0) &&
                                    (fRegWriteAddress == this.RegWriteAddress) &&
                                    (fReadCount == this.RegReadCount) &&
                                    (fReadAddress == this.RegReadAddress))    // 收到数据与标识的数据长度相符
                                {
                                    this.RegReadCount = (ushort)(fDataLen / 2);
                                    ReplyValues = new ushort[this.RegReadCount];
                                    for (int i = 0; i < this.RegReadCount; i++)
                                    {
                                        ReplyValues[i] = ReplyDatas[2 * i + 10];
                                        ReplyValues[i] = (ushort)((ReplyValues[i] << 8) | ReplyDatas[2 * i + 11]);
                                    }
                                    fErrorCode = this.RegReadCount > 0 ? this.RegReadCount : 1;
                                }
                            }
                            break;
                        default:
                            fErrorCode = -3;
                            break;
                    }
                else if ((ReplyDatas.Length >= 3) && ((ReplyDatas[1] | 0x80) == (int)this.Command))
                {
                    this.ErrorCode = -ReplyDatas[2];
                    return ReplyDatas[2];
                }
            }
            fHasReply = fErrorCode > 0;
            if (this.OnGetRTURespon != null)
                OnGetRTURespon(this);
            return fErrorCode;
        }

        /// <summary>
        /// 解析收到的数据为Modbus命令
        /// </summary>
        /// <param name="PacketData"></param>
        /// <param name="ErrorCode">返回错误代码</param>
        /// <returns></returns>
        public static int AnsyModbusRTUPacket(byte[] PacketData)
        {
            int ErrorCode = 0;
            if ((PacketData != null) && (PacketData.Length >= 5))
            {
                ErrorCode = 1;
                switch (PacketData[1])
                {
                    case (byte)ModbusCommand.ReadBitReg_0x01:
                    case (byte)ModbusCommand.WriteBitReg_0x05:
                    case (byte)ModbusCommand.ReadInputReg_0x04:
                    case (byte)ModbusCommand.ReadMemoryReg_0x03:
                    case (byte)ModbusCommand.WriteOneMemReg_0x06:
                        if (PacketData.Length < 6)
                            ErrorCode = -11; // 数据帧错误
                        break;
                    case (byte)ModbusCommand.WriteMemoryReg_0x10:
                        if (PacketData.Length < 9)
                            ErrorCode = -11; // 数据帧错误
                        break;
                    case (byte)ModbusCommand.RWMemoryReg_0x17:
                        if (PacketData.Length < 13)
                            ErrorCode = -11; // 数据帧错误
                        break;
                    case (byte)ModbusCommand.HBHCCommand_0x41:
                    case (byte)ModbusCommand.HBHCCommand_0x42:
                        if (PacketData.Length < 10)
                            ErrorCode = -11; // 数据帧错误
                        break;
                    default:
                        ErrorCode = -1;  // 不支持命令
                        break;
                }
            }
            return ErrorCode;
        }

        public static int AnsyModbusRTUPacket(byte[] PacketData, ref TModbusRTUCommandV2 fMBRCommand)
        {
            int ErrorCode = 0;
            if ((fMBRCommand != null) && (AnsyModbusRTUPacket(PacketData) > 0))
            {
                switch (PacketData[1])
                {
                    case (byte)ModbusCommand.ReadBitReg_0x01:
                        {
                            //fMBRCommand = new TModbusRTUCommand(ModbusCommand.ReadInputReg_0x04);
                            fMBRCommand.fCommand = ModbusCommand.ReadBitReg_0x01;
                            fMBRCommand.PLCAddress = PacketData[0];
                            fMBRCommand.RegReadAddress = (ushort)GetInt(PacketData, 2);
                            fMBRCommand.RegReadCount = (ushort)GetInt(PacketData, 4);
                            ErrorCode = PacketData.Length;
                        }
                        break;
                    case (byte)ModbusCommand.WriteBitReg_0x05:
                        {
                            //fMBRCommand = new TModbusRTUCommand(ModbusCommand.ReadMemoryReg_0x03);
                            fMBRCommand.fCommand = ModbusCommand.WriteBitReg_0x05;
                            fMBRCommand.PLCAddress = PacketData[0];
                            fMBRCommand.RegWriteAddress = (ushort)GetInt(PacketData, 2);
                            fMBRCommand.RegWriteCount = 1;
                            fMBRCommand.RegValue[0] = (ushort)GetInt(PacketData, 4);
                            ErrorCode = PacketData.Length;
                        }
                        break;
                    case (byte)ModbusCommand.ReadInputReg_0x04:
                        {
                            //fMBRCommand = new TModbusRTUCommand(ModbusCommand.ReadInputReg_0x04);
                            fMBRCommand.fCommand = ModbusCommand.ReadInputReg_0x04;
                            fMBRCommand.PLCAddress = PacketData[0];
                            fMBRCommand.RegReadAddress = (ushort)GetInt(PacketData, 2);
                            fMBRCommand.RegReadCount = (ushort)GetInt(PacketData, 4);
                            ErrorCode = PacketData.Length;
                        }
                        break;
                    case (byte)ModbusCommand.ReadMemoryReg_0x03:
                        {
                            //fMBRCommand = new TModbusRTUCommand(ModbusCommand.ReadMemoryReg_0x03);
                            fMBRCommand.fCommand = ModbusCommand.ReadMemoryReg_0x03;
                            fMBRCommand.PLCAddress = PacketData[0];
                            fMBRCommand.RegReadAddress = (ushort)GetInt(PacketData, 2);
                            fMBRCommand.RegReadCount = (ushort)GetInt(PacketData, 4);
                            ErrorCode = PacketData.Length;
                        }
                        break;
                    case (byte)ModbusCommand.WriteOneMemReg_0x06:
                        {
                            //fMBRCommand = new TModbusRTUCommand(ModbusCommand.ReadMemoryReg_0x03);
                            fMBRCommand.fCommand = ModbusCommand.WriteOneMemReg_0x06;
                            fMBRCommand.PLCAddress = PacketData[0];
                            fMBRCommand.RegWriteAddress = (ushort)GetInt(PacketData, 2);
                            fMBRCommand.RegWriteCount = 1;
                            fMBRCommand.RegValue[0] = (ushort)GetInt(PacketData, 4);
                            ErrorCode = PacketData.Length;
                        }
                        break;
                    case (byte)ModbusCommand.WriteMemoryReg_0x10:
                        {
                            //fMBRCommand = new TModbusRTUCommand(ModbusCommand.WriteMemoryReg_0x10);
                            fMBRCommand.fCommand = ModbusCommand.WriteMemoryReg_0x10;
                            fMBRCommand.PLCAddress = PacketData[0];
                            fMBRCommand.RegWriteAddress = (ushort)GetInt(PacketData, 2);
                            int fBCount = PacketData[6]; // 字节数
                            if ((fBCount != (PacketData.Length - 7)) || (fBCount != (GetInt(PacketData, 4) * 2)))
                                fMBRCommand.ErrorCode = -2;
                            else
                            {
                                fMBRCommand.RegWriteCount = (ushort)GetInt(PacketData, 4);
                                for (int i = 0; i < fMBRCommand.RegWriteCount; i++)
                                    fMBRCommand.RegValue[i] = (ushort)GetInt(PacketData, 7 + (i * 2));
                            }
                            ErrorCode = PacketData.Length;
                        }
                        break;
                    case (byte)ModbusCommand.RWMemoryReg_0x17:
                        {
                            //fMBRCommand = new TModbusRTUCommand(ModbusCommand.RWMemoryReg_0x17);
                            fMBRCommand.fCommand = ModbusCommand.RWMemoryReg_0x17;
                            fMBRCommand.PLCAddress = PacketData[0];
                            fMBRCommand.RegReadAddress = (ushort)GetInt(PacketData, 2);
                            fMBRCommand.RegReadCount = (ushort)GetInt(PacketData, 4);
                            fMBRCommand.RegWriteAddress = (ushort)GetInt(PacketData, 6);
                            int fBCount = PacketData[10]; // 字节数
                            if (fBCount != (PacketData.Length - 11) || (fBCount != (2 * GetInt(PacketData, 8))))
                                fMBRCommand.ErrorCode = -2;
                            else
                            {
                                fMBRCommand.RegWriteCount = (ushort)GetInt(PacketData, 8);
                                for (int i = 0; i < fMBRCommand.RegWriteCount; i++)
                                    fMBRCommand.RegValue[i] = (ushort)GetInt(PacketData, 11 + (i * 2));
                            }
                            ErrorCode = PacketData.Length;
                        }
                        break;
                    case (byte)ModbusCommand.HBHCCommand_0x41:
                        {
                            //fMBRCommand = new TModbusRTUCommand(ModbusCommand.HBHCCommand_0x41);
                            fMBRCommand.fCommand = ModbusCommand.HBHCCommand_0x41;
                            fMBRCommand.PLCAddress = PacketData[0];
                            fMBRCommand.RegReadAddress = (ushort)GetInt(PacketData, 2);
                            fMBRCommand.RegReadCount = (ushort)GetInt(PacketData, 4);
                            fMBRCommand.RegWriteAddress = (ushort)GetInt(PacketData, 6);
                            fMBRCommand.RegWriteCount = (ushort)GetInt(PacketData, 8);
                            if ((fMBRCommand.RegWriteCount != 0)
                                && ((PacketData.Length - 10 != (2 * fMBRCommand.RegWriteCount))))
                                fMBRCommand.ErrorCode = -2;
                            else
                            {
                                if (fMBRCommand.RegWriteCount > 0)
                                    for (int i = 0; i < fMBRCommand.RegWriteCount; i++)
                                        fMBRCommand.RegValue[i] = (ushort)GetInt(PacketData, 10 + (i * 2));
                            }
                            ErrorCode = PacketData.Length;
                        }
                        break;


                    case (byte)ModbusCommand.HBHCCommand_0x42:
                        {
                            fMBRCommand.fCommand = ModbusCommand.HBHCCommand_0x42;
                            fMBRCommand.PLCAddress = PacketData[0];
                            fMBRCommand.RegWriteAddress = (ushort)GetInt(PacketData, 2);
                            fMBRCommand.RegReadAddress = (ushort)GetInt(PacketData, 4);
                            fMBRCommand.RegReadCount = (ushort)GetInt(PacketData, 6);

                            int fDatasLen = GetInt(PacketData, 8);
                            if ((PacketData.Length - 10 == fDatasLen)
                                && (fDatasLen % 2 == 0))
                            {
                                fMBRCommand.RegWriteCount = (ushort)(fDatasLen / 2);

                                for (int i = 0; i < fMBRCommand.RegWriteCount; i++)
                                    fMBRCommand.RegValue[i] = (ushort)GetInt(PacketData, 10 + (i * 2));
                            }
                            ErrorCode = PacketData.Length;
                        }
                        break;
                    default:
                        ErrorCode = -1;  // 不支持命令                            
                        break;
                }
            }
            return ErrorCode;
        }

        #region 命令应答
        /// <summary>
        /// Modbus命令处理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="fMBCommand"></param>
        /// <returns></returns>
        public int ModbusResponCommand(out byte[] fResponData)
        {
            int fResult = 0;
            fResponData = new byte[0];
            if (ErrorCode >= 0)
            {
                // 所有应答的寄存器数据都从RegValue中获得
                switch (this.Command)
                {
                    case ModbusCommand.ReadBitReg_0x01:
                        ErrorCode = fResponReadBitReg(out fResponData);
                        break;
                    case ModbusCommand.WriteBitReg_0x05:
                        ErrorCode = fResponWriteBitReg(out fResponData);
                        break;
                    case ModbusCommand.ReadInputReg_0x04:
                    case ModbusCommand.ReadMemoryReg_0x03:
                        ErrorCode = fResponReadRegs(out fResponData);
                        break;
                    case ModbusCommand.WriteOneMemReg_0x06:
                        ErrorCode = fResponWriteOneMemReg(out fResponData);
                        break;
                    case ModbusCommand.WriteMemoryReg_0x10:
                        ErrorCode = fResponWriteMemoryReg(out fResponData);
                        break;
                    case ModbusCommand.RWMemoryReg_0x17:
                        ErrorCode = fResponRWMemoryReg(out fResponData);
                        break;
                    case ModbusCommand.HBHCCommand_0x41:
                        ErrorCode = fResponHBHCCommand0x41(out fResponData);
                        break;

                    case ModbusCommand.HBHCCommand_0x42:
                        ErrorCode = fResponHBHCCommand0x42(out fResponData);
                        break;

                    default:
                        ErrorCode = -1;
                        break;
                }
            }
            if (ErrorCode < 0)
            {
                fResponData = new byte[3];
                fResponData[0] = PLCAddress;
                fResponData[1] = (byte)((int)this.Command + 0x80);
                fResponData[2] = (byte)(-ErrorCode);
                fResult = 3;
            }
            return fResult;
        }

        public byte[] ModbusResponCommand()
        {
            byte[] fResponData = new byte[0];
            ModbusResponCommand(out fResponData);
            return fResponData;
        }
        protected int fResponHBHCCommand0x41(out byte[] fResponData)
        {
            int fResult = 0;
            List<byte> fResBuf = new List<byte>();
            fResBuf.Add(PLCAddress);                    // [0]  ：PLC地址
            fResBuf.Add((byte)Command);                 // [1]  ：命令代码
            fResBuf.AddRange(GetBytes(RegReadAddress));   // [2-3] :命令读取地址
            fResBuf.AddRange(GetBytes(ReplyValues.Length));    // [4-5]：实际数据量

            fResBuf.AddRange(GetBytes(RegWriteAddress));   // [6-7] :命令写入地址
            fResBuf.AddRange(GetBytes(RegWriteCount));    // [8-9]：写入数据量
                                                          // 读取寄存器
            for (int i = 0; i < ReplyValues.Length; i++)
                fResBuf.AddRange(GetBytes(ReplyValues[i]));
            fResponData = fResBuf.ToArray();
            fResult = fResponData.Length;
            return fResult;
        }

        protected int fResponHBHCCommand0x42(out byte[] fResponData)
        {
            int fResult = 0;
            List<byte> fResBuf = new List<byte>();
            fResBuf.Add(PLCAddress);                    // [0]  ：PLC地址
            fResBuf.Add((byte)Command);                 // [1]  ：命令代码
            fResBuf.AddRange(GetBytes(RegWriteAddress));   // [2-3] :主命令代码,RegWriteAddress
            fResBuf.AddRange(GetBytes(RegReadAddress));    // [4-5]：子命令代码,RegReadAddress
            fResBuf.AddRange(GetBytes(RegReadCount));   // [6-7] :秘钥代码,RegReadCount
            fResBuf.AddRange(GetBytes(ReplyValues.Length * 2));    // [8-9]：携带数据的数据量，单位：字节

            for (int i = 0; i < ReplyValues.Length; i++)
                fResBuf.AddRange(GetBytes(ReplyValues[i]));
            fResponData = fResBuf.ToArray();
            fResult = fResponData.Length;
            return fResult;
        }
        /// <summary>
        /// 读取线圈
        /// </summary>
        /// <param name="fMBCommand"></param>
        /// <param name="fResponData"></param>
        /// <returns></returns>
        protected int fResponReadBitReg(out byte[] fResponData)
        {
            int fResult = 0;
            fResponData = new byte[0];
            List<byte> fResBuf = new List<byte>();
            if ((this.RegReadCount > 0x7D0) || (this.RegReadCount <= 0))
                fResult = -3;//0x0001≤寄存器的数量≤0x07D0
            else
                if (this.ReplyValues.Length != this.RegReadCount)
                fResult = -2;//没有获得正确数量的数据
            else
            {
                fResBuf.Add(this.PLCAddress);
                fResBuf.Add((byte)this.Command);
                int fiCount = 0;
                if ((this.RegReadCount % 8) > 0)
                    fiCount = this.RegReadCount / 8 + 1;
                else
                    fiCount = this.RegReadCount / 8;
                fResBuf.Add((byte)(fiCount & 0xFF));

                byte fiValue = 0;

                for (int i = 0; i < this.RegReadCount; i++)
                {
                    int fTemp = 0;
                    // 默认RegValue中存放的应答的数据
                    if (this.ReplyValues[i] != 0)
                        fTemp = 1;
                    fiValue = (byte)(fiValue | (fTemp << ((i % 8))));
                    if ((i % 8) == 7)
                    {
                        fResBuf.Add(fiValue);
                        fiValue = 0;
                        fiCount--;
                    }
                }
                if (fiCount > 0)
                    fResBuf.Add(fiValue);
                fResponData = fResBuf.ToArray();
                fResult = fResponData.Length;
            }
            return fResult;
        }
        /// <summary>
        /// 读取寄存器
        /// </summary>
        /// <param name="fMBCommand"></param>
        /// <param name="fResponData"></param>
        /// <returns></returns>
        protected int fResponReadRegs(out byte[] fResponData)
        {
            int fResult = 0;
            fResponData = new byte[0];
            List<byte> fResBuf = new List<byte>();
            if ((this.RegReadCount > 0x7D) || (this.RegReadCount <= 0))
                fResult = -3;//0x0001≤寄存器的数量≤0x007D
            else
                if (this.ReplyValues.Length != this.RegReadCount)
                fResult = -2;//没有获得正确数量的数据
            else
            {
                fResBuf.Add(this.PLCAddress);
                fResBuf.Add((byte)this.Command);
                fResBuf.Add((byte)(this.RegReadCount * 2));
                for (int i = 0; i < this.RegReadCount; i++)
                    fResBuf.AddRange(GetBytes(ReplyValues[i]));
                fResponData = fResBuf.ToArray();
                fResult = fResponData.Length;
            }
            return fResult;
        }
        /// <summary>
        /// 写入保持寄存器
        /// </summary>
        /// <param name="fMBCommand"></param>
        /// <param name="fResponData"></param>
        /// <returns></returns>
        protected int fResponWriteMemoryReg(out byte[] fResponData)
        {
            int fResult = 0;
            fResponData = new byte[0];
            List<byte> fResBuf = new List<byte>();
            if (ErrorCode == -2)//字节数＝寄存器数x2 放在接收数据到命令的预处理中
                fResult = ErrorCode;
            else
            {
                if ((RegWriteCount > 0x7B) || (RegWriteCount <= 0))
                    fResult = -3;//0x0001≤寄存器的数量≤0x007B
                else
                {
                    fResBuf.Add(PLCAddress);
                    fResBuf.Add((byte)Command);
                    fResBuf.AddRange(GetBytes(RegWriteAddress));
                    fResBuf.AddRange(GetBytes(RegWriteCount));
                    fResponData = fResBuf.ToArray();
                    fResult = fResponData.Length;
                }
            }
            return fResult;
        }
        /// <summary>
        /// 写入线圈
        /// </summary>
        /// <param name="fMBCommand"></param>
        /// <param name="fResponData"></param>
        /// <returns></returns>
        protected int fResponWriteBitReg(out byte[] fResponData)
        {
            int fResult = 0;
            fResponData = new byte[0];
            List<byte> fResBuf = new List<byte>();
            if (ErrorCode == -2)//字节数＝寄存器数x2 放在接收数据到命令的预处理中
                fResult = ErrorCode;
            else
            {
                if ((RegWriteCount != 1) || ((RegValue[0] != 0) && (RegValue[0] != 0xFF00)))
                    fResult = -3;//输出值＝0x0000或0xFF00
                else
                    if (this.RegValue.Length != this.RegReadCount)
                    fResult = -2;//没有获得正确数量的数据
                else
                {
                    fResBuf.Add(PLCAddress);
                    fResBuf.Add((byte)Command);
                    fResBuf.AddRange(GetBytes(RegWriteAddress));
                    fResBuf.AddRange(GetBytes(RegValue[0]));
                    fResponData = fResBuf.ToArray();
                    fResult = fResponData.Length;
                }
            }
            return fResult;
        }
        /// <summary>
        /// 写入单个寄存器
        /// </summary>
        /// <param name="fMBCommand"></param>
        /// <param name="fResponData"></param>
        /// <returns></returns>
        protected int fResponWriteOneMemReg(out byte[] fResponData)
        {
            int fResult = 0;
            List<byte> fResBuf = new List<byte>();

            fResBuf.Add(PLCAddress);
            fResBuf.Add((byte)Command);
            fResBuf.AddRange(GetBytes(RegWriteAddress));
            fResBuf.AddRange(GetBytes(RegValue[0]));
            fResponData = fResBuf.ToArray();
            fResult = fResponData.Length;
            return fResult;
        }
        /// <summary>
        /// 读取后写入保持寄存器
        /// </summary>
        /// <param name="fMBCommand"></param>
        /// <param name="fResponData"></param>
        /// <returns></returns>
        protected int fResponRWMemoryReg(out byte[] fResponData)
        {
            int fResult = 0;
            fResponData = new byte[0];
            List<byte> fResBuf = new List<byte>();

            if ((RegReadCount > 0x7D) || (RegReadCount <= 0) ||
                (RegWriteCount > 0x7B) || (RegWriteCount <= 0))
                fResult = -3;//0x0001≤寄存器的数量≤0x007D
            else
             if (this.ReplyValues.Length != this.RegReadCount)
                fResult = -2;//没有获得正确数量的数据
            else
            {
                fResBuf.Add(PLCAddress);
                fResBuf.Add((byte)Command);
                fResBuf.Add((byte)RegReadCount);
                // 读取寄存器
                for (int i = 0; i < RegReadCount; i++)
                    fResBuf.AddRange(GetBytes(ReplyValues[i]));
                fResponData = fResBuf.ToArray();
                fResult = fResponData.Length;
            }
            return fResult;
        }
        /// <summary>
        /// 设置命令携带的数据
        /// </summary>
        /// <param name="WriteRegValues">需要携带的数据</param>
        /// <returns></returns>
        public int SetWriteRegValues(byte[] WriteRegValues)
        {
            fRegValue = new ushort[0];
            if ((WriteRegValues != null) && (WriteRegValues.Length % 2 == 0))
            {
                fRegValue = new ushort[WriteRegValues.Length / 2];
                for (int i = 0; i < fRegValue.Length; i++)
                {
                    fRegValue[i] = WriteRegValues[i * 2 + 1];
                    fRegValue[i] <<= 8;
                    fRegValue[i] |= WriteRegValues[i * 2 + 0];
                }
            }
            return fRegValue.Length;
        }

        public int SetWriteRegValues(ushort[] WriteRegValues)
        {
            fRegValue = new ushort[0];
            if (WriteRegValues != null)
                fRegValue = WriteRegValues;
            return fRegValue.Length;
        }

        #endregion

        #region 基础函数
        /// <summary>
        /// 将整数转换为数组，高位在前
        /// </summary>
        /// <param name="value"></param>
        /// <param name="lenth">转换后数组长度，默认为2位，代表2字节，16比特</param>
        /// <returns></returns>
        public static byte[] GetBytes(int value, int lenth = 2)
        {
            byte[] fBuf = null;
            if ((lenth <= 0) || (lenth >= 4))
                fBuf = new byte[4];
            else
                fBuf = new byte[lenth];

            // BitConverter.GetBytes()函数默认为低位在前
            Array.Copy(BitConverter.GetBytes(value), fBuf, fBuf.Length);
            // 反转数组，实现高位在前
            Array.Reverse(fBuf);
            return fBuf;
        }
        /// <summary>
        /// 将数组转换为整数，高位在前
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static int GetInt(byte[] data)
        {
            return GetInt(data, 0);
        }
        /// <summary>
        /// 将数组转换为整数，高位在前
        /// </summary>
        /// <param name="data"></param>
        /// <param name="startIndex">数组起始位置</param>
        /// <param name="lenth">要转换数组长度</param>
        /// <returns></returns>
        public static int GetInt(byte[] data, int startIndex, int lenth = 2)
        {
            byte[] fBuf = null;
            if (data.Length > startIndex)
            {
                if ((lenth <= 0) || (lenth >= 4))
                {
                    if (data.Length - startIndex < 4)
                        fBuf = new byte[data.Length - startIndex];
                    else
                        fBuf = new byte[4];
                }
                else
                {
                    if (data.Length - startIndex < lenth)
                        fBuf = new byte[data.Length - startIndex];
                    else
                        fBuf = new byte[lenth];
                }
                // 从源数组中将需要的数据复制到新的数组中
                for (int i = 0; i < fBuf.Length; i++)
                    fBuf[i] = data[startIndex + i];
                // 反转数组，有高位在前，变为低位在前
                Array.Reverse(fBuf);
                // 补足4位，从而实现转换为整数
                byte[] ftemp = new byte[4];
                Array.Copy(fBuf, ftemp, fBuf.Length);
                // BitConverter.ToInt32()函数默认为低位在前              
                return BitConverter.ToInt32(ftemp, 0);
            }
            else
                return -1;
        }
        /// <summary>
        /// 翻转数据，实现切换高位在前和低位在前
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        protected static byte[] ReverseEndian(byte[] data)
        {
            Array.Reverse(data);
            return data;
        }
        /// <summary>
        /// 从数组中截取形成新数组
        /// </summary>
        /// <param name="data"></param>
        /// <param name="startIndex"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        public static byte[] SubArray(byte[] data, int startIndex, int length)
        {
            byte[] fResult = new byte[0];
            if (startIndex + length <= data.Length)
            {
                fResult = new byte[length];
                for (int i = 0; i < fResult.Length; i++)
                    fResult[i] = data[i + startIndex];
            }
            return fResult;
        }
        #endregion

        /*
        public override bool Equals(object obj)
        {
            bool fResult = base.Equals(obj);

            if (fResult)
            {
                TModbusRTUCommandV2 fDest = (TModbusRTUCommandV2)obj;
                fResult = (fDest.Command==this.Command)&&(fDest.PLCAddress==this.PLCAddress)
                    &&(fDest.RegReadAddress==this.RegReadAddress)&&(fDest.RegReadCount==this.RegReadCount)

            }
            return fResult;
        }
        */

        /// <summary>
        /// 检查收到的数据量是否已经符合Modbus协议结束
        /// 注意：检查的数据不包括CRC校验码；主要是上位机有足够的计算能力，因此先计算CRC
        /// </summary>
        /// <param name="fDatas"></param>
        /// <returns></returns>
        static public bool CheckResponseComplete(byte[] fDatas)
        {
            // 数据中不携带有CRC校验码
            bool fResult = false;
            if ((fDatas != null) && (fDatas.Length >= 3) && (fDatas[0] < 0x7F))
            {
                if ((fDatas[1] > 0x7F) && (fDatas.Length == 3))
                    fResult = true;
                else
                    switch ((ModbusCommand)fDatas[1])
                    {
                        case ModbusCommand.ReadBitReg_0x01:
                        case ModbusCommand.ReadInputReg_0x04:
                        case ModbusCommand.ReadMemoryReg_0x03:
                        case ModbusCommand.RWMemoryReg_0x17:
                            // 协议中字节数为全部字节数量
                            if ((fDatas.Length - 3 == fDatas[2]) && (fDatas[2] > 0))               // 收到数据与标识的数据长度相符
                                fResult = true;
                            break;
                        case ModbusCommand.WriteBitReg_0x05:
                        case ModbusCommand.WriteOneMemReg_0x06:
                        case ModbusCommand.WriteMemoryReg_0x10:
                            if (fDatas.Length == 6)
                                fResult = true;
                            break;
                        case ModbusCommand.HBHCCommand_0x41:
                        case ModbusCommand.HBHCCommand_0x42:
                            if (fDatas.Length >= 10)
                            {
                                int fDataCount = fDatas[8];
                                fDataCount = (fDataCount << 8) | fDatas[9];
                                if (fDataCount == fDatas.Length - 10)
                                    fResult = true;
                            }
                            break;
                        default:
                            break;
                    }
            }
            return fResult;
        }
    }

    /// <summary>
    /// Modbus TCPIP命令对象
    /// </summary>
    public class TModbusTCPIPCommandV2 : TModbusRTUCommandV2
    {

        public event TMBCommandResponCallBack OnGetTCPIPRespon;
        /// <summary>
        /// 传输ID
        /// </summary>
        public ushort TransactionID { get; set; }
        /// <summary>
        /// 协议ID
        /// </summary>
        public ushort ProtocalID { get; set; }

        public TModbusTCPIPCommandV2() : this(ModbusCommand.ReadMemoryReg_0x03)
        {
            TransactionID = 0;
            ProtocalID = 0;
        }
        public TModbusTCPIPCommandV2(ModbusCommand MBCommand)
        {
            fCommand = MBCommand;
        }
        /// <summary>
        /// 获得Modbus命令的TCPIP数据帧
        /// </summary>
        /// <param name="PacketData"></param>
        /// <returns></returns>
        public int GetTCPIPPacketData(out byte[] PacketData)
        {
            List<byte> fTCPHead = new List<byte>();
            int fResult = this.GetPacketDataNoCRC(out PacketData);
            if (fResult > 0)
            {
                fTCPHead.AddRange(TModbusRTUCommandV2.GetBytes(this.TransactionID, 2));
                fTCPHead.AddRange(TModbusRTUCommandV2.GetBytes(this.ProtocalID, 2));
                fTCPHead.AddRange(TModbusRTUCommandV2.GetBytes(PacketData.Length, 2));
                fTCPHead.AddRange(PacketData);
                PacketData = fTCPHead.ToArray();
                fResult += 6;
            }
            return fResult;
        }

        public byte[] GetTCPIPPacketData()
        {
            byte[] fResult = new byte[0];
            GetTCPIPPacketData(out fResult);
            return fResult;
        }

        public byte[] GetTCPIPResponData(byte[] ResponData)
        {
            List<byte> fTCPHead = new List<byte>();
            fTCPHead.AddRange(TModbusRTUCommandV2.GetBytes(this.TransactionID, 2));
            fTCPHead.AddRange(TModbusRTUCommandV2.GetBytes(this.ProtocalID, 2));
            fTCPHead.AddRange(TModbusRTUCommandV2.GetBytes(ResponData.Length, 2));
            fTCPHead.AddRange(ResponData);
            return fTCPHead.ToArray();
        }

        public byte[] GetTCPIPResponData()
        {
            List<byte> fTCPHead = new List<byte>();
            byte[] fResponData = this.ModbusResponCommand();
            if (fResponData.Length > 0)
            {
                fTCPHead.AddRange(TModbusRTUCommandV2.GetBytes(this.TransactionID, 2));
                fTCPHead.AddRange(TModbusRTUCommandV2.GetBytes(this.ProtocalID, 2));
                fTCPHead.AddRange(TModbusRTUCommandV2.GetBytes(fResponData.Length, 2));
                fTCPHead.AddRange(fResponData);
            }
            return fTCPHead.ToArray();
        }
        /// <summary>
        /// 将数据流转化为命令
        /// |     域     |  长度 |   描述                           |  客户机服务器    |
        /// |事务元标识符|2字节  |MODBUS请求/响应事务处理的识别码   |客户机启动        |服务器从接收的请求中重新复制
        /// |协议标识符  |2字节  |0=MODBUS协议                      |客户机启动        |服务器从接收的请求中重新复制
        /// |长度        |2字节  |以下字节的数量                    |客户机启动（请求）|服务器（响应）启动
        /// </summary>
        /// <param name="PacketData"></param>
        /// <param name="fMBTCommand"></param>
        /// <returns></returns>
        protected static int AnsyModbusTCPIPPacket(byte[] PacketData)
        {
            if ((PacketData != null)
                && (PacketData.Length >= 5 + 6)                         // 收到的数据长度符合最低要求
                && (PacketData[2] == 0)// && (PacketData[3] == 0)         // 协议ID=0; 判断协议ID为MODBUS
                                       // 协议ID高位为0，支持低位表达不同协议
                && (GetInt(PacketData, 4) == PacketData.Length - 6))    // 收到的数据正确
                return 1;
            else
                return 0;
        }
        public static int AnsyModbusTCPIPPacket(byte[] PacketData, out TModbusTCPIPCommandV2 fMBTCommand)
        {
            int ErrorCode = 0;
            fMBTCommand = new TModbusTCPIPCommandV2();
            if (AnsyModbusTCPIPPacket(PacketData) == 1)   // 收到的数据正确
            {
                fMBTCommand.TransactionID = (ushort)GetInt(PacketData, 0);
                fMBTCommand.ProtocalID = (ushort)GetInt(PacketData, 2);
                TModbusRTUCommandV2 fTemp = fMBTCommand;
                ErrorCode = AnsyModbusRTUPacket(SubArray(PacketData, 6, PacketData.Length - 6),
                    ref fTemp);
            }
            return ErrorCode;
        }
        /// <summary>
        /// 检查TCPIP获得数据是否是本命令的应答
        /// </summary>
        /// <param name="ReplyDatas"></param>
        /// <returns></returns>
        public int CheckTCPIPReply(byte[] ReplyDatas)
        {
            int ErrorCode = 0;
            if (ReplyDatas == null)
                ErrorCode = -1;
            else
            {
                // 判断长度
                if (ErrorCode >= 0)
                {
                    int fDataLen = ReplyDatas[4];
                    fDataLen = (fDataLen << 8) | ReplyDatas[5];
                    if ((ReplyDatas.Length >= 8) && (ReplyDatas.Length - 6 == fDataLen))
                    {
                        int fResTID = ReplyDatas[0];
                        fResTID <<= 8;
                        fResTID |= ReplyDatas[1];
                        // 检查事务处理标识符
                        if (fResTID == this.TransactionID)
                            ErrorCode = base.CheckReply(SubArray(ReplyDatas, 6, ReplyDatas.Length - 6));
                        else
                            ErrorCode = -4; //事务标识符错误
                    }
                    else
                        ErrorCode = -3;  // 长度错误
                }
            }
            if (OnGetTCPIPRespon != null)
                OnGetTCPIPRespon(this);
            return ErrorCode;
        }
    }

    public enum TModbusRegType
    {
        BitReg = 1,
        InputReg = 2,
        MemoryReg = 3,
    }

    public interface TModbusRegister
    {
        /// <summary>
        /// 获得寄存器大小
        /// </summary>
        /// <returns></returns>
        int GetRegSize();
        /// <summary>
        /// 设置寄存器大小
        /// </summary>
        /// <param name="RegSize">要设置的值</param>
        /// <returns>成功设置，返回寄存器大小，否则返回0</returns>
        int SetRegSize(int RegSize);
        /// <summary>
        /// 获得所有寄存器值
        /// </summary>
        /// <returns>寄存器数据</returns>
        ushort[] GetAllRegData();
        /// <summary>
        /// 获得寄存器指定地址的数据
        /// </summary>
        /// <param name="RegAddress">寄存器地址</param>
        /// <param name="RegValue">返回要读取的寄存器数据</param>
        /// <returns>地址正确返回1，否则返回0</returns>
        int GetRegValue(ushort RegAddress, out ushort RegValue);
        /// <summary>
        /// 写入数据到寄存器中
        /// </summary>
        /// <param name="RegAddress">寄存器地址</param>
        /// <param name="RegValue">要写入到寄存器的数据</param>
        /// <returns>地址正确返回1，否则返回0</returns>
        int SetRegValue(ushort RegAddress, ushort RegValue);
    }
    public class TModbusRegBase : TModbusRegister
    {
        /// <summary>
        /// 寄存器缓冲区
        /// </summary>
        public ushort[] Registers { get; set; }
        /// <summary>
        /// 寄存器大小
        /// </summary>
        public int RegSize
        {
            get { return Registers.Length; }
            set { Registers = new ushort[value]; }
        }
        /// <summary>
        /// 寄存器类型
        /// </summary>
        public int RegType { get; set; }

        #region 构建函数
        public ushort this[int i]
        {
            get
            {
                ushort fValue = 0;
                if (GetRegValue((ushort)i, out fValue) > 0)
                    return fValue;
                else
                    throw new Exception("地址超界！");
            }
            set
            {
                SetRegValue((ushort)i, value);
            }
        }
        public TModbusRegBase()
        {
            Registers = new ushort[0];
            RegType = 0;
        }

        public TModbusRegBase(int RegisterSize) : this()
        {
            Registers = new ushort[RegisterSize];
        }

        public TModbusRegBase(int RegisterSize, int RegisterType) : this(RegisterSize)
        {
            RegType = RegisterType;
        }
        #endregion

        #region TModbusRegister接口
        /// <summary>
        /// 获得寄存器大小
        /// </summary>
        /// <returns></returns>
        public int GetRegSize()
        {
            return RegSize;
        }
        /// <summary>
        /// 设置寄存器大小
        /// </summary>
        /// <param name="RegSize">要设置的值</param>
        /// <returns>成功设置，返回寄存器大小，否则返回0</returns>
        public int SetRegSize(int RegSize)
        {
            this.RegSize = RegSize;
            return this.RegSize;
        }
        /// <summary>
        /// 获得所有寄存器值
        /// </summary>
        /// <returns>寄存器数据</returns>
        public ushort[] GetAllRegData()
        {
            List<ushort> fBuf = new List<ushort>(Registers);
            return fBuf.ToArray();
        }
        /// <summary>
        /// 获得寄存器指定地址的数据
        /// </summary>
        /// <param name="RegAddress">寄存器地址</param>
        /// <param name="RegValue">返回要读取的寄存器数据</param>
        /// <returns>地址正确返回1，否则返回0</returns>
        public int GetRegValue(ushort RegAddress, out ushort RegValue)
        {
            RegValue = 0;
            if ((RegAddress >= 0) && (RegAddress < RegSize))
            {
                RegValue = Registers[RegAddress];
                return 1;
            }
            else
                return 0;
        }
        /// <summary>
        /// 写入数据到寄存器中
        /// </summary>
        /// <param name="RegAddress">寄存器地址</param>
        /// <param name="RegValue">要写入到寄存器的数据</param>
        /// <returns>地址正确返回1，否则返回0</returns>        
        public int SetRegValue(ushort RegAddress, ushort RegValue)
        {
            if ((RegAddress >= 0) && (RegAddress < RegSize))
            {
                Registers[RegAddress] = RegValue;
                return 1;
            }
            else
                return 0;
        }
        #endregion
    }

    /// <summary>
    /// Modbus寄存器对象
    /// </summary>
    public class TModbusRegisters
    {
        #region 成员
        protected int fBitRegSize
        {
            get { return BitReg01x.GetRegSize(); }
            set { BitReg01x.SetRegSize(value); }
        }
        /// <summary>
        /// 线圈(开关量)寄存器 fc.0,1
        /// </summary>
        public TModbusRegBase BitReg01x { get; set; }


        /// <summary>
        /// 输入寄存器数量
        /// </summary>
        protected ushort fInputRegSize
        {
            get { return (ushort)InputReg4x.Length; }
            set { InputReg4x = new ushort[value]; }
        }

        /// <summary>
        /// 输入寄存器 fc.4
        /// </summary>
        public ushort[] InputReg4x { get; set; }
        /// <summary>
        /// 保持寄存器数量
        /// </summary>
        protected ushort fMemoryRegSize
        {
            get { return (ushort)MemoryReg3x.Length; }
            set { MemoryReg3x = new ushort[value]; }
        }
        /// <summary>
        /// 保持寄存器 fc.3
        /// </summary>
        public ushort[] MemoryReg3x { get; set; }

        #endregion

        public TModbusRegisters()
        {
            BitReg01x = new TModbusRegBase(0);
        }

        public TModbusRegisters(ushort BitRegSize, ushort InputRegSize, ushort MemoryRegSize) : this()
        {
            if (BitRegSize > 0)
                BitReg01x.RegSize = BitRegSize;
            fInputRegSize = InputRegSize;
            fMemoryRegSize = MemoryRegSize;
        }
        /// <summary>
        /// 读取PLC寄存器数据
        /// </summary>
        /// <param name="fRegType">寄存器类型</param>
        /// <param name="fRegAddress">寄存器地址</param>
        /// <param name="fRegData">返回寄存器数据</param>
        /// <returns>返回读取数据数量</returns>
        public int ReadRegData(TModbusRegType fRegType, ushort fRegAddress, out ushort fRegData)
        {
            int fResult = 0;
            fRegData = 0;
            switch (fRegType)
            {
                case TModbusRegType.BitReg:
                    fResult = BitReg01x.GetRegValue(fRegAddress, out fRegData);
                    break;
                case TModbusRegType.InputReg:
                    if (fRegAddress < this.fInputRegSize)
                    {
                        fRegData = this.InputReg4x[fRegAddress];
                        fResult++;
                    }
                    break;
                case TModbusRegType.MemoryReg:
                    if (fRegAddress < this.fMemoryRegSize)
                    {
                        fRegData = this.MemoryReg3x[fRegAddress];
                        fResult++;
                    }
                    break;
            }
            return fResult;
        }

        /// <summary>
        /// 将寄存器填充测试数据
        /// </summary>
        public void SetDemoValue()
        {
            for (int i = 0; i < fBitRegSize; i++)
                BitReg01x[i] = 0;
            for (int i = 0; i < fInputRegSize; i++)
                InputReg4x[i] = (ushort)i;
            for (int i = 0; i < fMemoryRegSize; i++)
                MemoryReg3x[i] = (ushort)i;
        }
    }
}
